home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Resources / Chat & Communication / Digsby build 37 / digsby_setup.exe / lib / smtplib.pyo (.txt) < prev    next >
Python Compiled Bytecode  |  2008-10-13  |  15KB  |  575 lines

  1. # Source Generated with Decompyle++
  2. # File: in.pyo (Python 2.5)
  3.  
  4. import socket
  5. import re
  6. import email.Utils as email
  7. import base64
  8. import hmac
  9. from email.base64MIME import encode as encode_base64
  10. from sys import stderr
  11. __all__ = [
  12.     'SMTPException',
  13.     'SMTPServerDisconnected',
  14.     'SMTPResponseException',
  15.     'SMTPSenderRefused',
  16.     'SMTPRecipientsRefused',
  17.     'SMTPDataError',
  18.     'SMTPConnectError',
  19.     'SMTPHeloError',
  20.     'SMTPAuthenticationError',
  21.     'quoteaddr',
  22.     'quotedata',
  23.     'SMTP']
  24. SMTP_PORT = 25
  25. CRLF = '\r\n'
  26. OLDSTYLE_AUTH = re.compile('auth=(.*)', re.I)
  27.  
  28. class SMTPException(Exception):
  29.     pass
  30.  
  31.  
  32. class SMTPServerDisconnected(SMTPException):
  33.     pass
  34.  
  35.  
  36. class SMTPResponseException(SMTPException):
  37.     
  38.     def __init__(self, code, msg):
  39.         self.smtp_code = code
  40.         self.smtp_error = msg
  41.         self.args = (code, msg)
  42.  
  43.  
  44.  
  45. class SMTPSenderRefused(SMTPResponseException):
  46.     
  47.     def __init__(self, code, msg, sender):
  48.         self.smtp_code = code
  49.         self.smtp_error = msg
  50.         self.sender = sender
  51.         self.args = (code, msg, sender)
  52.  
  53.  
  54.  
  55. class SMTPRecipientsRefused(SMTPException):
  56.     
  57.     def __init__(self, recipients):
  58.         self.recipients = recipients
  59.         self.args = (recipients,)
  60.  
  61.  
  62.  
  63. class SMTPDataError(SMTPResponseException):
  64.     pass
  65.  
  66.  
  67. class SMTPConnectError(SMTPResponseException):
  68.     pass
  69.  
  70.  
  71. class SMTPHeloError(SMTPResponseException):
  72.     pass
  73.  
  74.  
  75. class SMTPAuthenticationError(SMTPResponseException):
  76.     pass
  77.  
  78.  
  79. class SSLFakeSocket:
  80.     
  81.     def __init__(self, realsock, sslobj):
  82.         self.realsock = realsock
  83.         self.sslobj = sslobj
  84.  
  85.     
  86.     def send(self, str):
  87.         self.sslobj.write(str)
  88.         return len(str)
  89.  
  90.     sendall = send
  91.     
  92.     def close(self):
  93.         self.realsock.close()
  94.  
  95.  
  96.  
  97. class SSLFakeFile:
  98.     
  99.     def __init__(self, sslobj):
  100.         self.sslobj = sslobj
  101.  
  102.     
  103.     def readline(self):
  104.         str = ''
  105.         chr = None
  106.         while chr != '\n':
  107.             chr = self.sslobj.read(1)
  108.             str += chr
  109.         return str
  110.  
  111.     
  112.     def close(self):
  113.         pass
  114.  
  115.  
  116.  
  117. def quoteaddr(addr):
  118.     m = (None, None)
  119.     
  120.     try:
  121.         m = email.Utils.parseaddr(addr)[1]
  122.     except AttributeError:
  123.         pass
  124.  
  125.     if m == (None, None):
  126.         return '<%s>' % addr
  127.     elif m is None:
  128.         return '<>'
  129.     else:
  130.         return '<%s>' % m
  131.  
  132.  
  133. def quotedata(data):
  134.     return re.sub('(?m)^\\.', '..', re.sub('(?:\\r\\n|\\n|\\r(?!\\n))', CRLF, data))
  135.  
  136.  
  137. class SMTP:
  138.     debuglevel = 0
  139.     file = None
  140.     helo_resp = None
  141.     ehlo_resp = None
  142.     does_esmtp = 0
  143.     
  144.     def __init__(self, host = '', port = 0, local_hostname = None):
  145.         self.esmtp_features = { }
  146.         if host:
  147.             (code, msg) = self.connect(host, port)
  148.             if code != 220:
  149.                 raise SMTPConnectError(code, msg)
  150.             
  151.         
  152.         if local_hostname is not None:
  153.             self.local_hostname = local_hostname
  154.         else:
  155.             fqdn = socket.getfqdn()
  156.             if '.' in fqdn:
  157.                 self.local_hostname = fqdn
  158.             else:
  159.                 addr = '127.0.0.1'
  160.                 
  161.                 try:
  162.                     addr = socket.gethostbyname(socket.gethostname())
  163.                 except socket.gaierror:
  164.                     pass
  165.  
  166.                 self.local_hostname = '[%s]' % addr
  167.  
  168.     
  169.     def set_debuglevel(self, debuglevel):
  170.         self.debuglevel = debuglevel
  171.  
  172.     
  173.     def connect(self, host = 'localhost', port = 0):
  174.         if not port and host.find(':') == host.rfind(':'):
  175.             i = host.rfind(':')
  176.             if i >= 0:
  177.                 host = host[:i]
  178.                 port = host[i + 1:]
  179.                 
  180.                 try:
  181.                     port = int(port)
  182.                 except ValueError:
  183.                     raise socket.error, 'nonnumeric port'
  184.                 except:
  185.                     None<EXCEPTION MATCH>ValueError
  186.                 
  187.  
  188.             None<EXCEPTION MATCH>ValueError
  189.         
  190.         if not port:
  191.             port = SMTP_PORT
  192.         
  193.         if self.debuglevel > 0:
  194.             print >>stderr, 'connect:', (host, port)
  195.         
  196.         msg = 'getaddrinfo returns an empty list'
  197.         self.sock = None
  198.         for res in socket.getaddrinfo(host, port, 0, socket.SOCK_STREAM):
  199.             (af, socktype, proto, canonname, sa) = res
  200.             
  201.             try:
  202.                 self.sock = socket.socket(af, socktype, proto)
  203.                 if self.debuglevel > 0:
  204.                     print >>stderr, 'connect:', sa
  205.                 
  206.                 self.sock.connect(sa)
  207.             except socket.error:
  208.                 msg = None
  209.                 if self.debuglevel > 0:
  210.                     print >>stderr, 'connect fail:', msg
  211.                 
  212.                 if self.sock:
  213.                     self.sock.close()
  214.                 
  215.                 self.sock = None
  216.                 continue
  217.  
  218.             break
  219.         
  220.         if not self.sock:
  221.             raise socket.error, msg
  222.         
  223.         (code, msg) = self.getreply()
  224.         if self.debuglevel > 0:
  225.             print >>stderr, 'connect:', msg
  226.         
  227.         return (code, msg)
  228.  
  229.     
  230.     def send(self, str):
  231.         if self.debuglevel > 0:
  232.             print >>stderr, 'send:', repr(str)
  233.         
  234.         if self.sock:
  235.             
  236.             try:
  237.                 self.sock.sendall(str)
  238.             except socket.error:
  239.                 self.close()
  240.                 raise SMTPServerDisconnected('Server not connected')
  241.             except:
  242.                 None<EXCEPTION MATCH>socket.error
  243.             
  244.  
  245.         None<EXCEPTION MATCH>socket.error
  246.         raise SMTPServerDisconnected('please run connect() first')
  247.  
  248.     
  249.     def putcmd(self, cmd, args = ''):
  250.         if args == '':
  251.             str = '%s%s' % (cmd, CRLF)
  252.         else:
  253.             str = '%s %s%s' % (cmd, args, CRLF)
  254.         self.send(str)
  255.  
  256.     
  257.     def getreply(self):
  258.         resp = []
  259.         if self.file is None:
  260.             self.file = self.sock.makefile('rb')
  261.         
  262.         while None:
  263.             line = self.file.readline()
  264.             if line == '':
  265.                 self.close()
  266.                 raise SMTPServerDisconnected('Connection unexpectedly closed')
  267.             
  268.             if self.debuglevel > 0:
  269.                 print >>stderr, 'reply:', repr(line)
  270.             
  271.             code = line[:3]
  272.             
  273.             try:
  274.                 errcode = int(code)
  275.             except ValueError:
  276.                 errcode = -1
  277.                 break
  278.  
  279.             if line[3:4] != '-':
  280.                 break
  281.                 continue
  282.             continue
  283.             errmsg = '\n'.join(resp)
  284.             if self.debuglevel > 0:
  285.                 print >>stderr, 'reply: retcode (%s); Msg: %s' % (errcode, errmsg)
  286.             
  287.         return (errcode, errmsg)
  288.  
  289.     
  290.     def docmd(self, cmd, args = ''):
  291.         self.putcmd(cmd, args)
  292.         return self.getreply()
  293.  
  294.     
  295.     def helo(self, name = ''):
  296.         if not name:
  297.             pass
  298.         self.putcmd('helo', self.local_hostname)
  299.         (code, msg) = self.getreply()
  300.         self.helo_resp = msg
  301.         return (code, msg)
  302.  
  303.     
  304.     def ehlo(self, name = ''):
  305.         self.esmtp_features = { }
  306.         if not name:
  307.             pass
  308.         self.putcmd('ehlo', self.local_hostname)
  309.         (code, msg) = self.getreply()
  310.         if code == -1 and len(msg) == 0:
  311.             self.close()
  312.             raise SMTPServerDisconnected('Server not connected')
  313.         
  314.         self.ehlo_resp = msg
  315.         if code != 250:
  316.             return (code, msg)
  317.         
  318.         self.does_esmtp = 1
  319.         resp = self.ehlo_resp.split('\n')
  320.         del resp[0]
  321.         for each in resp:
  322.             auth_match = OLDSTYLE_AUTH.match(each)
  323.             if auth_match:
  324.                 self.esmtp_features['auth'] = self.esmtp_features.get('auth', '') + ' ' + auth_match.groups(0)[0]
  325.                 continue
  326.             
  327.             m = re.match('(?P<feature>[A-Za-z0-9][A-Za-z0-9\\-]*) ?', each)
  328.             if m:
  329.                 feature = m.group('feature').lower()
  330.                 params = m.string[m.end('feature'):].strip()
  331.                 if feature == 'auth':
  332.                     self.esmtp_features[feature] = self.esmtp_features.get(feature, '') + ' ' + params
  333.                 else:
  334.                     self.esmtp_features[feature] = params
  335.             feature == 'auth'
  336.         
  337.         return (code, msg)
  338.  
  339.     
  340.     def has_extn(self, opt):
  341.         return opt.lower() in self.esmtp_features
  342.  
  343.     
  344.     def help(self, args = ''):
  345.         self.putcmd('help', args)
  346.         return self.getreply()[1]
  347.  
  348.     
  349.     def rset(self):
  350.         return self.docmd('rset')
  351.  
  352.     
  353.     def noop(self):
  354.         return self.docmd('noop')
  355.  
  356.     
  357.     def mail(self, sender, options = []):
  358.         optionlist = ''
  359.         if options and self.does_esmtp:
  360.             optionlist = ' ' + ' '.join(options)
  361.         
  362.         self.putcmd('mail', 'FROM:%s%s' % (quoteaddr(sender), optionlist))
  363.         return self.getreply()
  364.  
  365.     
  366.     def rcpt(self, recip, options = []):
  367.         optionlist = ''
  368.         if options and self.does_esmtp:
  369.             optionlist = ' ' + ' '.join(options)
  370.         
  371.         self.putcmd('rcpt', 'TO:%s%s' % (quoteaddr(recip), optionlist))
  372.         return self.getreply()
  373.  
  374.     
  375.     def data(self, msg):
  376.         self.putcmd('data')
  377.         (code, repl) = self.getreply()
  378.         if self.debuglevel > 0:
  379.             print >>stderr, 'data:', (code, repl)
  380.         
  381.         if code != 354:
  382.             raise SMTPDataError(code, repl)
  383.         else:
  384.             q = quotedata(msg)
  385.             if q[-2:] != CRLF:
  386.                 q = q + CRLF
  387.             
  388.             q = q + '.' + CRLF
  389.             self.send(q)
  390.             (code, msg) = self.getreply()
  391.             if self.debuglevel > 0:
  392.                 print >>stderr, 'data:', (code, msg)
  393.             
  394.             return (code, msg)
  395.  
  396.     
  397.     def verify(self, address):
  398.         self.putcmd('vrfy', quoteaddr(address))
  399.         return self.getreply()
  400.  
  401.     vrfy = verify
  402.     
  403.     def expn(self, address):
  404.         self.putcmd('expn', quoteaddr(address))
  405.         return self.getreply()
  406.  
  407.     
  408.     def login(self, user, password):
  409.         
  410.         def encode_cram_md5(challenge, user, password):
  411.             challenge = base64.decodestring(challenge)
  412.             response = user + ' ' + hmac.HMAC(password, challenge).hexdigest()
  413.             return encode_base64(response, eol = '')
  414.  
  415.         
  416.         def encode_plain(user, password):
  417.             return encode_base64('\x00%s\x00%s' % (user, password), eol = '')
  418.  
  419.         AUTH_PLAIN = 'PLAIN'
  420.         AUTH_CRAM_MD5 = 'CRAM-MD5'
  421.         AUTH_LOGIN = 'LOGIN'
  422.         if self.helo_resp is None and self.ehlo_resp is None:
  423.             if self.ehlo()[0] <= self.ehlo()[0]:
  424.                 pass
  425.             elif not self.ehlo()[0] <= 299:
  426.                 (code, resp) = self.helo()
  427.                 if code <= code:
  428.                     pass
  429.                 elif not code <= 299:
  430.                     raise SMTPHeloError(code, resp)
  431.                 
  432.             
  433.         
  434.         if not self.has_extn('auth'):
  435.             raise SMTPException('SMTP AUTH extension not supported by server.')
  436.         
  437.         authlist = self.esmtp_features['auth'].split()
  438.         preferred_auths = [
  439.             AUTH_CRAM_MD5,
  440.             AUTH_PLAIN,
  441.             AUTH_LOGIN]
  442.         authmethod = None
  443.         for method in preferred_auths:
  444.             if method in authlist:
  445.                 authmethod = method
  446.                 break
  447.                 continue
  448.         
  449.         if authmethod == AUTH_CRAM_MD5:
  450.             (code, resp) = self.docmd('AUTH', AUTH_CRAM_MD5)
  451.             if code == 503:
  452.                 return (code, resp)
  453.             
  454.             (code, resp) = self.docmd(encode_cram_md5(resp, user, password))
  455.         elif authmethod == AUTH_PLAIN:
  456.             (code, resp) = self.docmd('AUTH', AUTH_PLAIN + ' ' + encode_plain(user, password))
  457.         elif authmethod == AUTH_LOGIN:
  458.             (code, resp) = self.docmd('AUTH', '%s %s' % (AUTH_LOGIN, encode_base64(user, eol = '')))
  459.             if code != 334:
  460.                 raise SMTPAuthenticationError(code, resp)
  461.             
  462.             (code, resp) = self.docmd(encode_base64(password, eol = ''))
  463.         elif authmethod is None:
  464.             raise SMTPException('No suitable authentication method found.')
  465.         
  466.         if code not in (235, 503):
  467.             raise SMTPAuthenticationError(code, resp)
  468.         
  469.         return (code, resp)
  470.  
  471.     
  472.     def starttls(self, keyfile = None, certfile = None):
  473.         (resp, reply) = self.docmd('STARTTLS')
  474.         if resp == 220:
  475.             sslobj = socket.ssl(self.sock, keyfile, certfile)
  476.             self.sock = SSLFakeSocket(self.sock, sslobj)
  477.             self.file = SSLFakeFile(sslobj)
  478.             self.helo_resp = None
  479.             self.ehlo_resp = None
  480.             self.esmtp_features = { }
  481.             self.does_esmtp = 0
  482.         
  483.         return (resp, reply)
  484.  
  485.     
  486.     def sendmail(self, from_addr, to_addrs, msg, mail_options = [], rcpt_options = []):
  487.         if self.helo_resp is None and self.ehlo_resp is None:
  488.             if self.ehlo()[0] <= self.ehlo()[0]:
  489.                 pass
  490.             elif not self.ehlo()[0] <= 299:
  491.                 (code, resp) = self.helo()
  492.                 if code <= code:
  493.                     pass
  494.                 elif not code <= 299:
  495.                     raise SMTPHeloError(code, resp)
  496.                 
  497.             
  498.         
  499.         esmtp_opts = []
  500.         if self.does_esmtp:
  501.             if self.has_extn('size'):
  502.                 esmtp_opts.append('size=%d' % len(msg))
  503.             
  504.             for option in mail_options:
  505.                 esmtp_opts.append(option)
  506.             
  507.         
  508.         (code, resp) = self.mail(from_addr, esmtp_opts)
  509.         if code != 250:
  510.             self.rset()
  511.             raise SMTPSenderRefused(code, resp, from_addr)
  512.         
  513.         senderrs = { }
  514.         if isinstance(to_addrs, basestring):
  515.             to_addrs = [
  516.                 to_addrs]
  517.         
  518.         for each in to_addrs:
  519.             (code, resp) = self.rcpt(each, rcpt_options)
  520.             if code != 250 and code != 251:
  521.                 senderrs[each] = (code, resp)
  522.                 continue
  523.         
  524.         if len(senderrs) == len(to_addrs):
  525.             self.rset()
  526.             raise SMTPRecipientsRefused(senderrs)
  527.         
  528.         (code, resp) = self.data(msg)
  529.         if code != 250:
  530.             self.rset()
  531.             raise SMTPDataError(code, resp)
  532.         
  533.         return senderrs
  534.  
  535.     
  536.     def close(self):
  537.         if self.file:
  538.             self.file.close()
  539.         
  540.         self.file = None
  541.         if self.sock:
  542.             self.sock.close()
  543.         
  544.         self.sock = None
  545.  
  546.     
  547.     def quit(self):
  548.         self.docmd('quit')
  549.         self.close()
  550.  
  551.  
  552. if __name__ == '__main__':
  553.     import sys
  554.     
  555.     def prompt(prompt):
  556.         sys.stdout.write(prompt + ': ')
  557.         return sys.stdin.readline().strip()
  558.  
  559.     fromaddr = prompt('From')
  560.     toaddrs = prompt('To').split(',')
  561.     print 'Enter message, end with ^D:'
  562.     msg = ''
  563.     while None:
  564.         line = sys.stdin.readline()
  565.         if not line:
  566.             break
  567.         
  568.         msg = msg + line
  569.         continue
  570.         print 'Message length is %d' % len(msg)
  571.         server = SMTP('localhost')
  572.         server.sendmail(fromaddr, toaddrs, msg)
  573.         server.quit()
  574. __name__ == '__main__'
  575.